package owg.util.editor2d.modes;

import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;

import owg.util.data.Pair;
import owg.util.editor2d.ConstructorParams;
import owg.util.editor2d.Editor2D;
import owg.util.editor2d.Editor2D.Axes;
import owg.util.editor2d.Editor2D.Pivot;
import owg.util.editor2d.entity.Placeable2D;
import owg.util.euclidian.V2D;
import owg.util.opengl.EGL;

public class Translate extends TransformationMode {
	public static double SLOW_MULTIPLIER = 0.1;
	
	protected boolean absolute;
	protected V2D lastMouse;
	protected V2D tOffset;

	/**The current transformation axis.*/
	protected Editor2D.Axes axis;
	/**The location of the pivot object when starting the transformation.*/
	protected final V2D pivotStart;
	
	public Translate(Editor2D e, Editor2D.Axes axis, boolean absolute)
	{
		super(e, "Grab...");
		lastMouse = e.eventHandler().getMousePosition();
		tOffset = new V2D();
		this.absolute = absolute;

		pivotStart = new V2D();
		if(pivot != null)
			pivotStart.set(pivot.getX(), pivot.getY());
		this.axis = axis; 
	}
	
	@Override
	public void mouse(MouseEvent e) {
		if(e.getID() == MouseEvent.MOUSE_RELEASED)
		{
			if(e.getButton() == MouseEvent.BUTTON1)
				terminate(false);
			else if (e.getButton() == MouseEvent.BUTTON3)
				terminate(true);
		}
		else if((e.getID() == MouseEvent.MOUSE_MOVED || e.getID() == MouseEvent.MOUSE_DRAGGED) && numberValue == null)
			update(e.isShiftDown());
	}
	private void update(boolean slow)
	{
		if(pivot == null)
			return;//Do nothing
		V2D mpos = editor.eventHandler().getMousePosition();
		
		if(numberValue == null)
		{
			if(absolute)
				tOffset.set(mpos).add(-pivotStart.x(), -pivotStart.y()).multiply(slow?SLOW_MULTIPLIER:1);
			else
				tOffset.add(mpos.clone().sub(lastMouse), slow?SLOW_MULTIPLIER:1);
		}
		
		String numericStr = null;

		if(axis == Axes.X)
		{
			if(numberValue != null)
				tOffset.x(numberValue);
			tOffset.y(0);
			numericStr = numericalValueString(tOffset.x());
		}
		else if(axis == Axes.Y)
		{
			if(numberValue != null)
				tOffset.y(numberValue);
			tOffset.x(0);
			numericStr = numericalValueString(tOffset.y());
		}
		else if(axis == Axes.VIEW)
			numericStr = numericalValueString(tOffset.x())+", "+numericalValueString(tOffset.y());
		
		for (int i = 0; i < affectedIndices.length; i++)
		{
			int index = affectedIndices[i];
			Pair<Placeable2D, ConstructorParams> p = editor.worldObjectsImmutable.get(index);
			final Placeable2D localPivot;
			
			final V2D localOffset;
			if(axis == Axes.LOCAL_X || axis == Axes.LOCAL_Y)
			{
				if(pivotMode == Pivot.FIRST_SELECTED || pivotMode == Pivot.LAST_SELECTED)
					localPivot = pivot;
				else
					localPivot = p.a;
				
				final V2D localAxis;
				if(axis == Axes.LOCAL_X)
					localAxis = xOf(localPivot);
				else
					localAxis = yOf(localPivot);
				final double dotty;
				if(numberValue == null)
					dotty = tOffset.dot(localAxis);
				else
					dotty = numberValue;
				
				localOffset = localAxis.clone().multiply(dotty);
				if(p.a == pivot)
					numericStr = numericalValueString(dotty);
			}
			else
				localOffset = tOffset.clone();
			
			if(axis == Axes.X)
				localOffset.y(inverse.getData(i).y);
			else
				localOffset.p[1] += inverse.getData(i).y;
			if(axis == Axes.Y)
				localOffset.x(inverse.getData(i).x);
			else
				localOffset.p[0] += inverse.getData(i).x;
			
			editor.eventHandler().correctToGrid(localOffset, false);
			p.a.setLocation(localOffset.x(), localOffset.y());
		}

		editor.editorUI().replaceMessage("Grab("+axis+"): "+numericStr+((absolute&&numberValue==null)?"(Direct)":""));
		lastMouse.set(mpos);
	}

	@Override
	public void render(EGL<?> egl) 
	{}
	@Override
	public void key2(KeyEvent e) 
	{
		if(e.getKeyCode() == KeyEvent.VK_SHIFT && (e.getID() == KeyEvent.KEY_PRESSED || e.getID() == KeyEvent.KEY_RELEASED) && numberValue == null)
		{
			//Update when shift is toggled( but not in keyboard input mode, since slow does not apply there )
			update(e.isShiftDown());
		}
		else if(e.getID() == KeyEvent.KEY_PRESSED)
		{
			if(e.getKeyCode() == KeyEvent.VK_G)
				absolute = !absolute;
			else if(e.getKeyCode() == KeyEvent.VK_X)
			{
				if(axis == Axes.X)
					axis = Axes.LOCAL_X;
				else if(axis == Axes.LOCAL_X)
				{
					axis = Axes.VIEW;
					clearNumberInput();
				}
				else
					axis = Axes.X;
			}
			else if(e.getKeyCode() == KeyEvent.VK_Y)
			{
				if(axis == Axes.Y)
					axis = Axes.LOCAL_Y;
				else if(axis == Axes.LOCAL_Y)
				{
					axis = Axes.VIEW;
					clearNumberInput();
				}
				else
					axis = Axes.Y;
			}
			else if(e.getKeyCode() == KeyEvent.VK_ENTER)
			{
				terminate(false);
				return;
			}
			else if(e.getKeyCode() == KeyEvent.VK_ESCAPE)
			{
				terminate(true);
				return;
			}
			else
				return;
			//Update only if axis or absolute changed
			editor.modeListeners.fireEvents(e.getModifiers());
			update(e.isShiftDown());
		}
	}
	@Override
	protected void numberInputChanged(KeyEvent e)
	{
		if(numberValue == null)
			tOffset.set(V2D.ZERO);
		update(e==null?false:e.isShiftDown());
	}
	@Override
	protected boolean numberInputAllowed()
	{
		return axis != Axes.VIEW;
	}

	@Override
	protected String getMessage()
	{
		if(pivot == null)
			return "Move no objects...";
		if(axis == Axes.VIEW)
			return "Move objects by "+numericalValueString(pivot.getX()-pivotStart.x())+", "+
				numericalValueString(pivot.getY()-pivotStart.y());
		else if(axis == Axes.X)
			return "Move objects along X axis by "+numericalValueString(pivot.getX()-pivotStart.x());
		else if(axis == Axes.Y)
			return "Move objects along Y axis by "+numericalValueString(pivot.getY()-pivotStart.y());
		else 
			return "Move objects along "+axis+" by "+
				numericalValueString(new V2D(pivot.getX(), pivot.getY()).sub(pivotStart).dot((axis == Axes.LOCAL_X)?xOf(pivot):yOf(pivot)));
	}

	public Axes getAxis()
	{
		return axis;
	}
}
